package com.fc.advbox.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fc.advbox.dao.BaseDao;
import com.fc.advbox.dao.ContractDao;
import com.fc.advbox.dao.ContractEquipmentDao;
import com.fc.advbox.dao.EquipmentDao;
import com.fc.advbox.dto.contract.ContractTotalInfo;
import com.fc.advbox.entity.*;
import com.fc.advbox.service.IContractService;
import com.fc.advbox.service.IEquipmentHoldingService;
import com.fc.advbox.service.IOrgService;
import com.fc.advbox.utils.Constant;
import com.fc.advbox.utils.RRException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.fc.advbox.service.impl.OrgServiceImpl.DEFAULT_ORG_NAME;

/**
 * ContractServiceImpl
 *
 * @author Gary.Jiang
 * @date 2018/6/22.15:52
 */
@Service("contractService")
@Transactional
@Slf4j
public class ContractServiceImpl  extends BaseServiceImpl<ContractEntity> implements IContractService{

    @Autowired
    private ContractDao contractDao;

    @Autowired
    private EquipmentDao equipmentDao;

    @Autowired
    private ContractEquipmentDao contractEquipmentDao;

    @Autowired
    private IOrgService orgService;

    @Autowired
    private IEquipmentHoldingService equipmentHoldingService;

    @Override
    public BaseDao getDao() {
        return contractDao;
    }

    @Override
    public ContractEntity queryObject(Long contractId) {
        return contractDao.queryObject(contractId);
    }

    @Override
    public void save(ContractEntity entity) {
        log.info("Save contract:{}", entity);
        log.info("allocate equipment for {} contract.", entity.getType());

        AdvOrgEntity jiaOrgEntity = checkJiaOrg(entity);
        AdvOrgEntity yiOrgEntity = orgService.queryObject(entity.getYiOrgId());
        if(yiOrgEntity == null){
            throw new RRException("未找到乙方机构!");
        }

        entity.setJiaOrgId(jiaOrgEntity.getId());
        entity.setJiaOrgName(jiaOrgEntity.getName());
        entity.setYiOrgName(yiOrgEntity.getName());
        entity.setName(entity.getYiOrgName() + "垃圾箱合同");
        entity.setStatus(Constant.ContractStatus.DRAFTING.getValue()); // 保存合同信息， 新保存的合同状态为 drafting -- 草稿,保存
        contractDao.save(entity);

        // 保存合同中约定的设备
        saveContractEquipmentList(entity);

        // 只有在广告出租时才修改设备的状态 为 blocking -- 冻结，不可出租
        if(Constant.ContractType.RENT.getValue().equalsIgnoreCase(entity.getType())
                && entity.getEquipmentIds() != null
                && entity.getEquipmentIds().size() > 0)
        {
            equipmentDao.updateStatusBatch(Constant.EquipmentStatus.BLOCKING.getValue(), entity.getEquipmentIds());
        }
    }

    @Override
    public void update(ContractEntity entity) {
        log.info("Update contract:{}", entity);
        log.info("Contract type:{}.", entity.getType());

        checkJiaOrg(entity);
        ContractEntity rawEntity = contractDao.queryObject(entity.getId());
        if(!rawEntity.getType().equals(entity.getType())){
            log.warn("Contract type changed !");
            throw new RRException("合同类型不允许变动");
        }
        if(Constant.ContractStatus.CONFIRMED.getValue().equals(rawEntity.getStatus())) {
            throw new RRException("合同执行中,禁止修改!");
        }

        // 保存合同信息
        contractDao.update(entity);

        // 清空相关的设备列表
        contractEquipmentDao.deleteByContractId(entity.getId());

        // 重新插入相关设备
        saveContractEquipmentList(entity);
    }

    @Override
    public void delete(Long contractId) {
        ContractEntity contractEntity = contractDao.queryObject(contractId);
        if(contractEntity != null && !Constant.ContractStatus.DRAFTING.getValue().equals(contractEntity.getStatus())){
            throw new RRException("只有合同处于草稿状态下才能被删除!");
        }

        // 修改设备状态为 open
        List<Long> equipmentIds = contractEquipmentDao.queryEquipmentIdsByContractId(contractId);
        log.info("Renting equipments {}", equipmentIds);
        if(equipmentIds != null && equipmentIds.size() > 0){
            equipmentDao.updateStatusAndRentDateBatch(Constant.EquipmentStatus.OPEN.getValue(), null, null, equipmentIds);
        }

        // 删除合同record
        contractDao.delete(contractId);
    }

    @Override
    public List<ContractEntity> queryList(Map<String, Object> map) {
        return contractDao.queryList(map);
    }

    @Override
    public int queryTotal(Map<String, Object> map) {
        return contractDao.queryTotal(map);
    }

    /**
     * 确认合同
     * @param contractId
     */
    public void confirmContract(Long contractId){
        ContractEntity contractEntity = contractDao.queryObject(contractId);
        if(contractEntity == null){
            throw new RRException("合同未找到, 请核查ID!");
        }

        // 修改合同status 为 confirmed -- 已确定,已生效
        contractEntity.setStatus(Constant.ContractStatus.CONFIRMED.getValue());
        contractDao.update(contractEntity);

        // 修改设备状态为 renting -- 已出租，正在出租
        List<Long> equipmentIds = contractEquipmentDao.queryEquipmentIdsByContractId(contractId);
        log.info("Renting equipments {}", equipmentIds);
        if(Constant.ContractType.RENT.getValue().equalsIgnoreCase(contractEntity.getType())
                && equipmentIds != null
                && equipmentIds.size() > 0)
        {
            // 广告位出租的合同才更新设备出租时间
            equipmentDao.updateStatusAndRentDateBatch(Constant.EquipmentStatus.RENTING.getValue(),contractEntity.getStartDate(),contractEntity.getEndDate(), equipmentIds);
        }

        // 修改设备表关于代理商，渠道商等的日收益比例
        contractEntity.setEquipmentIds(equipmentIds);
        equipmentHoldingService.confirmContractToUpdateEquipmentRate(contractEntity);
    }

    /**
     * 终止合同
     * @param contractId
     * @param terminateDate
     */
    public void terminateContract(Long contractId, Date terminateDate){
        ContractEntity contractEntity = contractDao.queryObject(contractId);
        if(contractEntity == null){
            throw new RRException("合同未找到, 请核查ID!");
        }
        if(contractEntity != null && !Constant.ContractStatus.CONFIRMED.getValue().equals(contractEntity.getStatus())){
            throw new RRException("只有合同处于执行阶段才能中止!");
        }

        // 修改合同的到期时间和状态
        contractEntity.setStatus(Constant.ContractStatus.TERMINATION.getValue());
        contractEntity.setEndDate(terminateDate);
        contractDao.update(contractEntity);

        // 更新设备表中的状态
        List<Long> equipmentIds = contractEquipmentDao.queryEquipmentIdsByContractId(contractId);
        log.info("Reopen equipments {}", equipmentIds);
        if(equipmentIds != null && equipmentIds.size() > 0){
            equipmentDao.updateStatusAndRentDateBatch(Constant.EquipmentStatus.OPEN.getValue(),null,null, equipmentIds);
        }

        // 更新设备holding表中，对应乙方的利润分配截至时间和收益结束时间
        //终止把holding表中乙方相关数据置空
        contractEntity.setEquipmentIds(equipmentIds);
        contractEntity.setYiOrgId(null);
        contractEntity.setAmount(BigDecimal.ZERO);
        contractEntity.setStartDate(null);
        contractEntity.setEndDate(null);
        contractEntity.setBenifitRate(BigDecimal.ZERO);
        equipmentHoldingService.terminateEquipmentRateCalculation(contractEntity);
    }

    @Override
    public List<ContractEntity> queryContractsByEquipmentId(JSONObject params)
    {
        return contractEquipmentDao.queryContractsByEquipmentId(params);
    }

    @Override
    public ContractTotalInfo getContractTotalInfoByOrgId(JSONObject params) {
        return contractDao.getContractTotalInfoByOrgId(params);
    }

    private void saveContractEquipmentList(ContractEntity entity){
        if(entity.getEquipmentIds() != null && entity.getEquipmentIds().size() > 0){
            List<ContractEquipmentEntity> contractEquipmentList = new ArrayList<>();
            for(Long equipmentId: entity.getEquipmentIds()){
                ContractEquipmentEntity ceEntity = new ContractEquipmentEntity();
                ceEntity.setContractId(entity.getId());
                ceEntity.setEquipmentId(equipmentId);
                contractEquipmentList.add(ceEntity);
            }
            contractEquipmentDao.saveBatch(contractEquipmentList);
        }
    }

    private AdvOrgEntity checkJiaOrg(ContractEntity entity) {
        AdvOrgEntity defaultEntity = orgService.getDefaultOrg();
        Long ownerOrgId = defaultEntity != null ? defaultEntity.getId().longValue() : 0L;
        if(entity.getJiaOrgId() == null){
            entity.setJiaOrgId(ownerOrgId);
        }
        //不太明白为啥要抛错？
        if (!ownerOrgId.equals(entity.getJiaOrgId())) {
            log.warn("JiaOrg isn't the default Org {}", DEFAULT_ORG_NAME);
            throw new RRException(String.format("甲方不是默认机构 %s !", DEFAULT_ORG_NAME));
        }
        return defaultEntity;
    }
}
